package zzps.exeed.kernel.holder;

import zzps.exeed.kernel.core.PandaContainer;
import zzps.exeed.kernel.pandainjector.PandaInjector;
import zzps.exeed.kernel.tool.AnnotationTool;
import zzps.exeed.kernel.tool.ReflectTool;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class PandaHolder<T> {

    private Class<T> clazz;

    private T raw;
    private String name;
    private FieldHolder[] fields;
    private Map<Method,MethodHolder> methodHolderMap;//如果需要被代理会用到
    private Annotation[] annotations;
//    private AppContext context;


    public PandaHolder(Class<T> clazz) {
        this(clazz,null);

    }
    public PandaHolder(Class<T> clazz, T raw) {
        this(clazz,raw,null);
    }
    public PandaHolder(Class<T> clazz, T raw, String name) {
        this.clazz = clazz;
        this.raw = raw;
        this.name = name == null ? clazz.getCanonicalName():name;
        this.fields = getFields(clazz,new LinkedList<>());
        this.annotations = AnnotationTool.getAnnotations(clazz);
        if (raw == null) {
            init();
        } else {
            this.raw = raw;
        }
    }


    public Class<?> clazz() {
        return clazz;
    }
    public T raw() {
        return raw;
    }
    public T get() {
        return raw;
    }
    public void set(T t){
        raw = t;
    }

    public Annotation[] annotations(){
        return annotations;
    }

    private void init(){
        T instance = ReflectTool.newInstance(clazz);
        raw = instance;
//        inject();
    }

    public void inject(PandaContainer pandaContainer){
        for (FieldHolder field : fields) {
            Annotation[] anns = field.getAnnotations();
            for (Annotation ann : anns) {
                PandaInjector<Annotation> injector = (PandaInjector<Annotation>) pandaContainer.getPandaInjector(ann.annotationType());
                if (injector != null){
                    FieldValueInjector fieldValueInjector = new FieldValueInjector(field);
                    injector.inject(fieldValueInjector,ann, pandaContainer::injectPanda);
//                    return;
                }
            }
        }
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Map<Method, MethodHolder> methodHolderMap() {
        return methodHolderMap;
    }
    public void methodHolderMap(Map<Method, MethodHolder> methodHolderMap) {
        this.methodHolderMap = methodHolderMap;
    }

    public Method getMethod(String methodName){
        for (Map.Entry<Method, MethodHolder> entry : methodHolderMap.entrySet()) {
            Method method = entry.getKey();
            if (methodName.equals(method.getName())){
                return method;
            }
        }
        return null;
    }
    private FieldHolder[] getFields(Class<?> clazz, List<FieldHolder> list){
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            int modifiers = field.getModifiers();
            if (!Modifier.isFinal(modifiers)&&!Modifier.isTransient(modifiers)){
                list.add(new FieldHolder(this,field));
            }
        }
        Class<?> superclass = clazz.getSuperclass();
        if (superclass != Object.class){
            getFields(superclass,list);
        }
        return list.toArray(new FieldHolder[]{});
    }
}
